/*
 * Created on Apr 27, 2005
 *
 */
package littlecyberwar.ui.overlay;

import java.util.*;
import java.awt.*;
import java.awt.geom.*;
import littlecyberwar.ui.*;

/**
 * @author Milton  Soong
 *
 * This is a flyweight that can be used by many different element all with the same dimension
 */
public class OverlayInstance {

	/**
	 * Types of Overlay
	 */
	public static final String _Type="Type".intern();	// the key
	/**
	 * type of template where a uniform distance from the edge of the unit radiating outward
	 * e.g. used for ZOC and "touching".
	 */
	public static final String _Type_Border = "TypeBorder";
	
	/**
	 * type of template that's centrally radiated from the center of the unit
	 * e.g. COmmand range of commanders, or Warhammer style 
	 */
	public static final String  _Type_Center = "TypeCenter";
	
	/**
	 * Type of overlay from the a specific edge
	 * which edge is it (front, side, rear) is specified with another param.
	 * 
	 * e.g. DBx ZOC, shooting arc, etc. for front edge
	 */
	public static final String _Type_Edge = "TypeEdge";

	/**
	 * In case this is an edge, then we need the size of the edge where it's projected. (in pixels)
	 */
	public static final String _Type_Edge_Size = "TypeEdgeSize";

	/**
	 * Orientations
	 */
	public static final String _Orientation="Ori".intern();	// the key
	
	public static final String _Orientation_Front = "OrientationFront"; 
	public static final String _Orientation_Rear = "OrientationRear";
	public static final String _Orientation_Side = "OrientationSide";
	public static final String _Orientation_Right = "OrientationRight";
	public static final String _Orientation_Left = "OrientationLeft";
	
	/**
	 * Dimension
	 */
	
	public static final String _Dimension_distance = "DimensionDistance";	// the main distance from measuring point outward.
	public static final String _Dimension_angle = "DimensionAngle";			// the angle from perpendicular going outward.
	
	/**
	 * Rendering information
	 */
	public static final String _Color="Color".intern();
	public static final String _Alpha="Alpha".intern();	// the alpha value of the overlay 
	
	/**
	 * A cache where all existing instances are stored, 
	 * The key uses a naming convention of: type|(misc)
	 */
	private static HashMap cache = new HashMap();

	/**
	 * Instance variables
	 *
	 */
	private Area area;
	private AlphaComposite alphaComposit;	// the composite used to draw this type
	private Color color;
	
	private OverlayInstance() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	/**
	 * A factory method that returns an instance from a given model
	 * This is also cached into individual factory delegate for type
	 * 
	 * @author Milton  Soong
	 *
	 */
	public static OverlayInstance getInstance(HashMap attrib) {
		OverlayInstance ov = null;
		String type = (String)attrib.get(_Type);
		if ( type != null ){
			// there is a type. then find the matching inner factory class
			if ( type.equals(_Type_Border)){
				ov = getBorderInstance(attrib);
				
			} else if ( type.equals(_Type_Center)){
				ov = getCenterInstance(attrib);
				
			} else if ( type.equals(_Type_Edge)){
				ov = getEdgeInstance(attrib);
			}
			
		}
		
		return ( ov );
	}
	
	public static OverlayInstance getBorderInstance( HashMap hm ) {
		OverlayInstance ov = null;
		return ( ov );
	}
	
	public static OverlayInstance getCenterInstance( HashMap hm ) {
		OverlayInstance ov = null;
		return ( ov );
	}
	
	/**
	 * The edge instant have the following parameters that must be valid:
	 * _Orientation
	 * _Dimension_distance
	 * _Dimension_angle
	 * _Type_Edge_Size
	 * 
	 * first check the cache since it might be in there
	 * 
	 * @param hm the input hashmap that contains all the parameters needed
	 * @return
	 */
	public static OverlayInstance getEdgeInstance( HashMap hm ) {
		OverlayInstance ov = null;
		String o = (String)hm.get(_Orientation);
		Integer d = (Integer)hm.get(_Dimension_distance);
		Double a = (Double)hm.get(_Dimension_angle);
		Integer s = (Integer)hm.get(_Type_Edge_Size);
		Color c = (Color)hm.get(_Color);
		Float alpha = (Float)hm.get(_Alpha);
		
		String cacheKey = 0+d.toString()+a.toString()+s.toString();
		ov = (OverlayInstance)cache.get(cacheKey);
		if ( ov == null ){
			// nothing is in cache
			ov = constructEdgeInstance(o, d, a, s, c, alpha);
			cache.put(cacheKey, ov) ;
		} else {
			// it's already in cache, use that one
		}
		return ( ov );
	}
	
	private static OverlayInstance constructEdgeInstance(
			String o ,
			Integer d ,
			Double a ,
			Integer s,
			Color c,
			Float alpha
			) {
		OverlayInstance ov = null;
		if ( o.equals(_Orientation_Front)){
			ov = constructFrontEdgeInstance( d,a,s);			
		} else if ( o.equals(_Orientation_Rear)){
			ov = constructRearEdgeInstance( d,a,s);			
		} else if ( o.equals(_Orientation_Side)){
			ov = constructSideEdgeInstance( d,a,s);			
		} else if ( o.equals(_Orientation_Right)){
			ov = constructRightEdgeInstance( d,a,s);			
		} else if ( o.equals(_Orientation_Left)){			
			ov = constructLeftEdgeInstance( d,a,s);			
		}
		
		// now build the alpha composit that'll be used to draw ALL of this type
		ov.alphaComposit = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha.floatValue());
		ov.color = c;
		
		return ( ov );
	}
	
	/**
	 * This type contains a union of three Areas 
	 * 1) the main rectangle d x s,
	 * 2) a piece on ea side of an arc that's a radian(degree?)
	 * 
	 * @param d the distance out from the unit
	 * @param a the angle on both sides 
	 * @param s the size of the unit front edge
	 * @return
	 */
	private static OverlayInstance constructFrontEdgeInstance(
			Integer d ,
			Double a ,
			Integer s
			) {
		OverlayInstance ov = null;		
		Rectangle2D rec = new Rectangle2D.Double(0,-d.doubleValue(),s.doubleValue(), d.doubleValue());
		//Ellipse2D leftPie = new java.awt.geom.Ellipse2D.Double();
		
		ov = new OverlayInstance();
		ov.area = new Area(rec);
		return ( ov );
	}
	private static OverlayInstance constructRearEdgeInstance(
			Integer d ,
			Double a ,
			Integer s
			) {
		OverlayInstance ov = null;		
		
		return ( ov );
	}

	private static OverlayInstance constructSideEdgeInstance(
			Integer d ,
			Double a ,
			Integer s
			) {
		OverlayInstance ov = null;		
		
		return ( ov );
	}

	private static OverlayInstance constructRightEdgeInstance(
			Integer d ,
			Double a ,
			Integer s
			) {
		OverlayInstance ov = null;		
		
		return ( ov );
	}

	private static OverlayInstance constructLeftEdgeInstance(
			Integer d ,
			Double a ,
			Integer s
			) {
		OverlayInstance ov = null;		
		
		return ( ov );
	}

	public Shape getRuntime(Element el) {
		Shape rt = null;
		AffineTransform tr = el.getTransform();
		rt = tr.createTransformedShape(area);
		return ( rt );
	}
	/**
	 * @return Returns the alphaComposit.
	 */
	public AlphaComposite getAlphaComposit() {
		return alphaComposit;
	}
	/**
	 * @return Returns the color.
	 */
	public Color getColor() {
		return color;
	}
}
